/*
 * fileSystem.c
 *
 *  Created on: 21/09/2011
 *      Author: ayelenSanchez
 *      		danBalabunek
 *
 */
/***
 * Este es nuestro main, de acá tendría que arrancar todo, tiene que tener la implementación de Fuse
 */
#define FUSE_USE_VERSION 26

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include "colas.h"
#include "consola_pfs.h"
#include "archivos_abiertos.h"
#include "cluster.h"
#include "iniciarFat.h"
#include "estaticas.h"
#include "direccionamiento.h"
#include "estructuras.h"
#include "func_config.h"
#include "constantes.h"
#include "log.h"
#include "cache.h"
#include "conexiones.h"
#include <signal.h>
#include "signals.h"


//static const char *hello_str = "Hello World!\n";
//static const char *hello_path = "/hello";



static uint32_t LasRamonas_getattr(const char *path, struct stat *stbuf)
{
	if (memcmp("/.Trash", path, 7) == 0)
		return -ENOENT;
//	stbuf = (struct stat *) malloc (sizeof(struct stat)); 	// esta línea puede estar de más y hasta puede generar un error
															// hay que ver si stbuf, ya tiene memoria asiganada
	memset(stbuf, 0, sizeof(struct stat));

	stbuf->st_dev = bootSector->ID_NumeroDeSerie;

	char esDirectorio = 0;
	char *entrada, *nombreLargo;

	nombreLargo = (char *) malloc (15);
//	entrada = (char *) malloc (32); //tamaño entrada 32 bytes

	entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esDirectorio);


	if (esDirectorio == 1)
	{
		stbuf->st_mode = S_IFDIR | 0755;
		stbuf->st_nlink = 2;
		free(nombreLargo);
		free(entrada);

		return 0; // No se encontró el archivo
	}
	else
		if (entrada == NULL)
		{
			//stbuf->st_nlink = 0;
			free(nombreLargo);
			free(entrada);
			log_info(log, "PFS", "No se encontró %s", path);
			return -ENOENT;
		}


	stbuf->st_mode = S_IFREG | 0444;
	stbuf->st_nlink = 1;
	stbuf->st_size = obtenerTamanoArchivo(entrada);


	stbuf->st_blksize = TAMANO_CLUSTER;



	if (stbuf->st_size % bootSector->bytesPorSector)
		stbuf->st_blocks = (stbuf->st_size / bootSector->bytesPorSector ) + 1; // Number 512-byte blocks allocated. O sea, en sectores
	else
		stbuf->st_blocks = (stbuf->st_size / bootSector->bytesPorSector ); // Number 512-byte blocks allocated. O sea, en sectores

	free(nombreLargo);
	free(entrada);
	return 0;
}

/* EJEMPLO DE FUSE
static uint32_t LasRamonas_getattr(const char *path, struct stat *stbuf)
{
	uint32_t res = 0;
    memset(stbuf, 0, sizeof(struct stat));
    if(strcmp(path, "/") == 0) {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    }
    else if(strcmp(path, hello_path) == 0) {
        stbuf->st_mode = S_IFREG | 0444;
        stbuf->st_nlink = 1;
        stbuf->st_size = strlen(hello_str);
    }
    else
        res = -ENOENT;

    return res;
}
*/

static uint32_t LasRamonas_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                           off_t offset, struct fuse_file_info *fi)
{

	uint32_t iClus, cantNodosCola, cantidadEntradas, finCarpeta, i;
	char *entrada, *nombre, *carpeta;


	entrada = (char *) malloc (32);
	nombre = (char *) malloc (14);
	iClus = ObtenerClusterDeDirectorio(path);

	if (iClus == 0)
	{
		free(entrada);
		free(nombre);
		return -1;
	}

	struct colaCluster *cola;
	struct cluster *auxCluster = (struct cluster *) malloc (sizeof(struct cluster));
	auxCluster->numero = iClus;
	cola = CrearColaClusterDeEntradasDirectorio(auxCluster);

	cantNodosCola = CantidadDeNodosCola(cola);


	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	while(cola->frente != NULL)
		SacarDeColaCluster(cola);
	free(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32; /* 32 tamaño de entradas */
	finCarpeta = 0;

	uint32_t desde;

	if (strcmp(path,"/") == 0)
		desde = 0;
	else
	{
		desde = 2;
		filler(buf, ".", NULL, 0);
		filler(buf, "..", NULL, 0);
	}
	for (i = desde; i < cantidadEntradas && finCarpeta == 0; i++)
	{
		memcpy(entrada, carpeta + (i * 32),32);

		if (*entrada == 0)
			finCarpeta = 1;
		else
		{
			if (!EstaBorrado(entrada) && *entrada != 0)
			{
				if (*(entrada + 11) == ATRIBUTO_LFN)
				{
					obtenerNombreLargo(entrada, nombre);
					i++;
					memcpy(entrada, carpeta + (i * 32),32);
					if (!EstaBorrado(entrada))
						filler(buf, nombre, NULL, 0);

				}
				else
					if(*(entrada + 11) == ATRIBUTO_DIRECTORIO || /* OR */
							*(entrada + 11) == ATRIBUTO_ARCHIVO)
					{
						obtenerNombre(entrada, nombre);
						filler(buf, nombre, NULL, 0);
					}
			}

		}
	}

	free(entrada);
	free(nombre);
	free(auxCluster);
	free(carpeta);
	log_info(log, "PFS", "Se listó el directorio %s", path);
	return 0;
}

/*
 * Readdir de hello_fuse
  static uint32_t LasRamonas_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
                           off_t offset, struct fuse_file_info *fi)
  {
      (void) offset;
      (void) fi;

      if(strcmp(path, "/") != 0)
          return -ENOENT;

      filler(buf, ".", NULL, 0);
      filler(buf, "..", NULL, 0);
      filler(buf, hello_path + 1, NULL, 0);

      return 0;
  }
*/

static uint32_t LasRamonas_open(const char *path, struct fuse_file_info *fi)
{
	/* El "const char *path" siempre es la ruta absoluta  */

	uint32_t iClus = 0;
	char *nombre, *entrada;
	nombre = (char *) malloc (14);
//	entrada = (char *) malloc (32);
	char esdirectorio;
	entrada = ObtenerEntradaDeArchivo(path, nombre, &esdirectorio);

	if (entrada == NULL) /* Devuelve 0 si es error, sino devuelve número de Cluster */
	{
		printf ("El archivo no existe\n");
		free(nombre);
		free(entrada);
		log_error(log, "PFS", "No se encontró el archivo %s", path);
		return -1;
	}

	iClus = UbicacionCarpeta(entrada);


	pthread_mutex_lock(&mutexArchivosAbiertos);
	InsertarArchivoAbierto(&archivosAbiertos, path, iClus);
	pthread_mutex_unlock(&mutexArchivosAbiertos);

	log_info(log, "PFS", "Se abrió el archivo %s", path);


	free(nombre);
	free(entrada);
	return 0;
}



/*	 {
	  if(strcmp(path, hello_path) != 0)
          return -ENOENT; // el archivo no existe

      if((fi->flags & 3) == O_RDONLY)
      {
    	  /*

    	  Abrir como Sólo Lectura
    	  Revisar si ya está abierto
    	  Si ya fue abierto como Sólo Lectura, puede abrirse. Si fue abierto como
    	  escritura, también puede abrirse

    	  */
 /*     }

      if((fi->flags & 3) == O_WRONLY || (fi->flags & 3) == O_RDWR)
      {
    	  /*
    	   * Abrir como escritura
    	   * Si ya fue abierto como escritura, no puede abrirse.
    	   */

/*      }

      /* return -1 no se abrió el archivo */
/*      return 0; // se abrio el archivo
  }
*/

 /*
  * size es la cantidad de bytes a leer, la función retorna cantidad de bytes leidos
  * buf es el buffer donde se deben copiar los bytes solicitados
  * path es la ruta del archivo en el que hay que leer
  * offset: es la posición desde donde hay que leer "size" byte
  * read(): lee "size" bytes desde "offset" del srchivo "path",
  * y guarda los bytes leido en buf
  */


static uint32_t LasRamonas_read(const char *path, char *buf, size_t size, off_t offset,
                        struct fuse_file_info *fi)
{
	uint32_t length;
	uint32_t iClus;
	uint32_t auxSize = 0; // se usa para ir contando cuanto se leyó
	//uint32_t TAMANO_CLUSTER = (bootSector->sectoresPorCluster * bootSector->bytesPorSector);
	char *entrada, *cluster = NULL, *nombreLargo;
//	entrada = (char *) malloc (32); //tamaño de entrada de directorio
//	cluster = (char *) malloc (TAMANO_CLUSTER);
	nombreLargo = (char *) malloc (14); //tamaño maximo de nombre es 13

	char esdirectorio;

	entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esdirectorio);

	iClus = UbicacionCarpeta(entrada);
	length = obtenerTamanoArchivo(entrada);

	if (offset < length)
	{
		if (offset + size > length)
			size = length - offset;
	       	 /* leer archivo:  memcpy(buf, hello_str + offset, size);  */

		uint32_t primerClusterALeer = offset / TAMANO_CLUSTER; //nro de orden de cluster
		uint32_t ultimoClusterALeer = (offset + size) / TAMANO_CLUSTER; //nro de orden de cluster

			if ((offset + size) % TAMANO_CLUSTER == 0)
				ultimoClusterALeer--;

		uint32_t i = 0;
//		char *cluster;
//		cluster = (char *) malloc (TAMANO_CLUSTER);

		auxSize = size;

		pthread_mutex_lock(&mutexFat);
		for (i = 0; i < primerClusterALeer; i++) /*voy hasta primerluster */
		{
			 iClus = fat[iClus];
		}
		pthread_mutex_unlock(&mutexFat);

		cluster = SolicitarCluster(iClus, path);
		/* leo la cantidad necesario del primer cluster */
		memcpy (buf, cluster + (offset % TAMANO_CLUSTER), TAMANO_CLUSTER - (offset % TAMANO_CLUSTER));
		auxSize = auxSize - TAMANO_CLUSTER - (offset % TAMANO_CLUSTER);
		uint32_t j, k = 0;
		free(cluster);

		for (j = i + 1 ; j < ultimoClusterALeer ; j++) /* leo los cluster intermedios (se leen completos)*/
		{
			pthread_mutex_lock(&mutexFat);
			iClus = fat[iClus];
			pthread_mutex_unlock(&mutexFat);
			cluster = SolicitarCluster(iClus, path);
			memcpy (buf + TAMANO_CLUSTER - (offset % TAMANO_CLUSTER) + (k * TAMANO_CLUSTER), cluster, TAMANO_CLUSTER);
			auxSize = auxSize - TAMANO_CLUSTER;
			free(cluster);  /*OJOJOJOJOJOJO*/
			k++;
		}

		if (j == ultimoClusterALeer) /* leo lo que falta del último clusterdebe ocurrir siempre */
		{
			pthread_mutex_lock(&mutexFat);
			iClus = fat[iClus];
			pthread_mutex_unlock(&mutexFat);
			cluster = SolicitarCluster(iClus, path);
			memcpy (buf + TAMANO_CLUSTER - (offset % TAMANO_CLUSTER) + (k * TAMANO_CLUSTER), cluster, auxSize);
			free(cluster);
		}
		else {/*error*/}


	}
	else
		size = 0;

	free (entrada);
	free (nombreLargo);
	log_info (log, "PFS", "Lectura del archivo %s", path);
	return size;
}
 /* EJEMPLO DE FUSE

  {
      size_t len;
      (void) fi;
      if(strcmp(path, hello_path) != 0)
          return -ENOENT;

      len = strlen(hello_str);
      if (offset < len) {
          if (offset + size > len)
              size = len - offset;
          memcpy(buf, hello_str + offset, size);
      } else
          size = 0;

      return size; /* cantidad de bytes leidos
  } EJEMPLO DE FUSE */

static uint32_t LasRamonas_create (const char *path, mode_t mode, struct fuse_file_info *fi)
{									//crea y abre el archivo
	char *entrada, *entradaAux, *nombre, *carpeta, *cluster1, *cluster2;
	uint32_t cantNodosCola, iClus, cantidadEntradas, i, j, nuevoCluster, clusterEnCola, iClusLibre;
	struct cluster *st_clus;
	struct colaCluster *cola;
	struct nodoColaCluster *ptr;

	st_clus = (struct colaCluster *) malloc (sizeof(struct colaCluster));

	entrada = (char *) malloc (64); //32 bytes por entrada de directorio
	entradaAux = (char *) malloc (64); //32 bytes por entrada de directorio
//	nombre = (char *) malloc (14);

	nombre = obtenerNombreArchivoPath(path);

//	iClusLibre = SacarDeColaClusterLibres(clustersLibres);

	entrada = ArmarEntradaNombreLargo(entradaAux, nombre);
	ArmarEntradaNombreCortoNueva(entrada + 32, nombre, 0, ATRIBUTO_ARCHIVO);

	if ((iClus = ObtenerClusterDeDirectorio(path) )== 0)
	{/*error no existe el directorio destino*/}

	st_clus->numero = iClus;
	cola = CrearColaClusterDeEntradasDirectorio(st_clus);
	cantNodosCola = CantidadDeNodosCola(cola);

//	carpeta = calloc((cantNodosCola + 1) * TAMANO_CLUSTER, sizeof(char) );
	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32; /* 32 tamaño de entradas */

	for (i = 0; i < cantidadEntradas  &&  *(carpeta + (i * 32)) != 0 ; i++); // avanzo hasta el final o hasta encontrar una entrada vacía

	if (i >= cantidadEntradas - 1)
	{	// Si i es 4095 o 4096 debo agregar otro cluster a la carpeta para pegar el nombre largo
		// 4095 implica que solo hay un espacio y debo pegar 2
		// 4096 implica que la carpeta está llena y hay que agregar otro cluster para pegar la entrada

		nuevoCluster = AgregarUnClusterLibreAColaDeCluster(cola);
		cantNodosCola++;
		realloc(carpeta, TAMANO_CLUSTER);

	}
	memcpy(carpeta + (i * 32), entrada, 64);


	clusterEnCola = i / 128;
	ptr = cola->frente;

	for (j = 0; j < clusterEnCola; j++)
		ptr = ptr->sgte;

	cluster1 = carpeta + (j * TAMANO_CLUSTER);
	if ( ptr != cola->final)
	{
		cluster2 = carpeta + ((j+1) * TAMANO_CLUSTER);
		enviarCluster(ptr->sgte->numero, cluster2, 0);
	}

	enviarCluster(ptr->numero, cluster1, 0);

//	iClus = UbicacionCarpeta(entrada + 32);
	pthread_mutex_lock(&mutexArchivosAbiertos);
	InsertarArchivoAbierto(&archivosAbiertos, path, 0); //abro el archivo
	pthread_mutex_unlock(&mutexArchivosAbiertos);
//	fat[iClus] = EOC_MAXIMO;

	log_info(log, "PFS", "Se creo el archivo %s", path);
	free(carpeta);
	free(st_clus);
//	free (entrada);
	free (entradaAux);
	return 0;
}

static size_t LasRamonas_write (const char *path, const char *buffer, size_t size, off_t offset,
		  	  	  	  	  	  	  struct fuse_file_info *fi)
{

	struct colaBloquesFAT *bloques;
	bloques = (struct colaBloquesFAT *) malloc (sizeof(struct colaBloquesFAT));
	CrearColaBloqueFAT(bloques);

	char *entrada, esdirectorio, *nombreLargo;
	nombreLargo = (char *) malloc (14);
//	entrada = (char *) malloc (32);
	entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esdirectorio);
	if (entrada == NULL)
	{
		free(nombreLargo);
		free(bloques);
		return -1;
	}

	uint32_t length = obtenerTamanoArchivo(entrada);
	uint32_t iClus = UbicacionCarpeta(entrada);
	uint32_t iClusLibre;

	if (iClus == 0)
	{
		iClusLibre = SacarDeColaClusterLibres(clustersLibres);
		EscribirPosicion(entrada, iClusLibre);
		pthread_mutex_lock(&mutexFat);
		fat[iClusLibre] = EOC_MAXIMO;
		pthread_mutex_unlock(&mutexFat);
		MeterEnColaBloqueFAT(bloques, bloqueDeFat(iClusLibre));
		iClus = iClusLibre;
	}

	uint32_t yaEscrito = 0;

/*
	if (estaAbierto(path))
	{
		// archivo path está en uso. no puede truncarse
		return -1;
	}
*/

	struct colaCluster *cola;
	struct cluster *auxCluster = (struct cluster *) malloc (sizeof(struct cluster));
	auxCluster->numero = iClus;
	cola = CrearColaClusterDeEntradasDirectorio(auxCluster);
	free(auxCluster);

	int32_t i;

	if (length < offset + size)
	{


		uint32_t cantNodosTotales; //Cantidad de clusters totales para el nuevo tamaño de archivo (offset + size)
		uint32_t cantNodosActual; //Cantidad de clusters actuales que tiene asignado actualmente el archivo
		uint32_t cantNodosNuevosNecesarios;

		cantNodosTotales = ((offset + size) / TAMANO_CLUSTER) + 1;
		if ((offset + size) % 4096 == 0 )
			cantNodosTotales--;

		cantNodosActual = CantidadDeNodosCola(cola);

		cantNodosNuevosNecesarios = cantNodosTotales - cantNodosActual;

		uint32_t f;
		for (i = 0; i < cantNodosNuevosNecesarios; i++)
		{
			MeterEnColaBloqueFAT(bloques, bloqueDeFat(cola->final->numero));
			f = AgregarUnClusterLibreAColaDeCluster(cola);
			MeterEnColaBloqueFAT(bloques, bloqueDeFat(f));
		}

		EscribirTamano(entrada, offset + size);
		EscribirEntrada(path, entrada);

	}

	char *cluster;
//	cluster = calloc (TAMANO_CLUSTER, sizeof(char));

	/* pegar primer cluster*/
	int32_t primerCluster = offset / TAMANO_CLUSTER;	//primer cluster a ser actualizado
	int32_t ultimoCluster = (offset + size - 1) / TAMANO_CLUSTER; //ultimo cluster a ser actualizado

	int32_t comienzoPrimerParte = offset % TAMANO_CLUSTER;	//desde donde se actualiza el primer cluster
	int32_t cantidadClusterParaActualizar;

/*	cantidadClusterParaActualizar = (size / TAMANO_CLUSTER) + 1;
	if (offset % TAMANO_CLUSTER == 0)
		 cantidadClusterParaActualizar--;
*/


	struct nodoColaCluster *ptr;
	ptr = cola->frente;
	for (i = 0; i < primerCluster; i++)
		ptr = ptr->sgte;
	cluster = SolicitarCluster(ptr->numero, path); //iClus es el primer cluster del archivo

	/* AGREGADO */
	uint32_t sizeACopiar;
	if (size <= (TAMANO_CLUSTER - (offset % TAMANO_CLUSTER)))
		sizeACopiar = size;
	else
		sizeACopiar = TAMANO_CLUSTER - (offset % TAMANO_CLUSTER);
	/* AGREGADO */

	memcpy(cluster + comienzoPrimerParte, buffer, sizeACopiar); //saca TAMANO_CLUSTER - comienzoPrimerParte
	enviarCluster(ptr->numero, cluster, path);
	free(cluster);
	yaEscrito = sizeACopiar;
	/* fin pegar primer cluster */

	/*pegar cluster intermedios */
	char *intermedio;
	intermedio = buffer + (TAMANO_CLUSTER - comienzoPrimerParte);
	for(i = primerCluster + 1; i <= ultimoCluster - 1; i++) //los intermedios: desde el segundo hasta el anteúltimo
	{
		ptr = ptr->sgte;
		memcpy (cluster, intermedio + ((i-1) * TAMANO_CLUSTER), TAMANO_CLUSTER);
		enviarCluster(ptr->numero, cluster, path);
		yaEscrito = yaEscrito + TAMANO_CLUSTER;
	}
	/*FIN pegar cluster intermedios */

	/*Pegar último cluster */
	i++;
	if (primerCluster < ultimoCluster)
	{
		ptr = ptr->sgte;
		cluster = SolicitarCluster(ptr->numero, path);
		memcpy(cluster, intermedio + (i * TAMANO_CLUSTER), size - yaEscrito);
		enviarCluster(ptr->numero, cluster, path);
		yaEscrito = yaEscrito + ( size  - yaEscrito);
		free(cluster);
		/*FIN Pegar último cluster */
	}
	fi->writepage = 1;
	actualizarEnFat(bloques);

	struct nodoColaBloquesFAT *ptrBloque, *ptrBloqueAux;
	ptrBloque = bloques->frente;
	while( ptrBloque != NULL)
	{
		ptrBloqueAux = ptrBloque;
		ptrBloque = ptrBloque->sgte;
		free(ptrBloqueAux);
	}
	free(bloques);
	free (nombreLargo);

	struct nodoColaCluster *ptrAux;
	ptr = cola->frente;
	while(ptr != NULL)
	{
		ptrAux = ptr;
		ptr = ptr->sgte;
		free(ptrAux);
	}
	free(cola);
	free(entrada);

	log_info(log, "PFS", "Se escribió en archivo %s", path);
	return /*size; */ yaEscrito;
}

  static uint32_t LasRamonas_flush (const char *path, struct fuse_file_info *fi)
  {

	  pthread_mutex_lock(&mutexArchivosAbiertos);
	  borrarCache(path);
	  pthread_mutex_unlock(&mutexArchivosAbiertos);
	  return 0;

  }

  static uint32_t LasRamonas_release (const char *path, struct fuse_file_info *fi)
  {
	  pthread_mutex_lock(&mutexArchivosAbiertos);
	  BorrarArchivoAbierto(&archivosAbiertos, path);
	  pthread_mutex_unlock(&mutexArchivosAbiertos);
	  log_info(log, "PFS", "Se cerró el archivo %s", path);
	  return 0;

  }

  /*
   *  Al archivo "path" lo corta o lo amplia a el valor "size"
   */

  static uint32_t LasRamonas_truncate (const char *path, off_t size)
  {
	  struct colaBloquesFAT *bloques;
	  bloques = (struct colaBloquesFAT *) malloc (sizeof(struct colaBloquesFAT));
	  CrearColaBloqueFAT(bloques);

	  char *entrada, *nombreLargo, esDirectorio;
//	  entrada = (char *) malloc (32);
	  nombreLargo = (char *) malloc (14);
	  entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esDirectorio);
	  if (entrada == NULL || esDirectorio == 1)
		  return -1;

	  uint32_t length = obtenerTamanoArchivo(entrada);
	  uint32_t iClus = UbicacionCarpeta(entrada);

	  uint32_t cantidadClusterActual, nuevaCantidadCluster, i;
/*
	  if (estaAbierto(path))
	  {
		  // archivo path está en uso. no puede truncarse
		  return -1;
	  }
*/
	  if (length == size) /* no se hace nada */
		  return 0;

	  struct colaCluster *cola;
	  struct cluster *auxCluster = (struct cluster *) malloc (sizeof(struct cluster));
	  auxCluster->numero = iClus;
	  cola = CrearColaClusterDeEntradasDirectorio(auxCluster);
	  free(auxCluster);

	 // uint32_t TAMANO_CLUSTER = bootSector->bytesPorSector * bootSector->sectoresPorCluster;

	  if (length == 0)
	  {
		  cantidadClusterActual = 0;

		  while (!ColaClusterVacia(*cola))
		  	  SacarDeColaCluster(cola); // Si tiene 0 bytes, la cola queda con un cluster con cola->frente->numero = 0, entonces los saco
	  }
	  else
		  cantidadClusterActual = CantidadDeNodosCola(cola);
//		if(length % TAMANO_CLUSTER != 0)
//		cantidadClusterActual++;

	  if (size == 0)
		  nuevaCantidadCluster = 0;
	  else
	  {
		  nuevaCantidadCluster = size / TAMANO_CLUSTER;
	  	  if(size % TAMANO_CLUSTER != 0)
	  		  nuevaCantidadCluster++;
	  }

	  uint32_t f;
	  if (length < size) /* hay que aumentar el archivo */
	  	  for (i = 0; i < (nuevaCantidadCluster - cantidadClusterActual); i++)
	  	  {
	  		  if (cola->final != NULL)
	  		  	  MeterEnColaBloqueFAT(bloques, bloqueDeFat(cola->final->numero));
	  		  f = AgregarUnClusterLibreAColaDeCluster(cola);
	  		  MeterEnColaBloqueFAT(bloques, bloqueDeFat(f));
	  	  }


	  else /* hay que reducir el archivo */
		  for (i = 0; i < (cantidadClusterActual - nuevaCantidadCluster); i++)
		  {
			  MeterEnColaBloqueFAT(bloques, bloqueDeFat(cola->final->numero));
			  f = RemoverUltimoClusterDeColaDeCluster(cola);
			  if (f != 0)
			  	  MeterEnColaBloqueFAT(bloques, bloqueDeFat(f));
		  }

	  if (size == 0)
		  EscribirPosicion(entrada, 0);
	  else
		  EscribirPosicion(entrada, cola->frente->numero);

	  EscribirTamano(entrada, size);
	  EscribirEntrada(path, entrada);

	  actualizarEnFat(bloques);
	  while(cola->frente != NULL)
		  SacarDeColaCluster(cola);

	  free(cola);
	  free(entrada);
	  free(bloques);

	  log_info (log, "PFS", "Se truncó el archivo %s" ,path);
	  return 0;
  }



  /* borrar el archivo "path" */
static uint32_t LasRamonas_unlink (const char *path)
{
	uint32_t iClus, cantNodosCola, i, cantidadEntradas, clusterArchivo, clusterEnCola, f, j;
	struct colaCluster *cola;

	struct nodoColaCluster *ptr, *ptrAux;
	char *carpeta, *ptrCarpeta, *entrada, *nombreLargo, *entradaLarga, *cluster1, *cluster2, esDirectorio;
	struct colaBloquesFAT *bloques;
	bloques = (struct colaBloquesFAT *) malloc (sizeof(struct colaBloquesFAT));

//	entrada = (char *) calloc (32 * 2, 1); // tamaño de entrada es 32 bytes *2 (por nombre largo)
	nombreLargo = (char *) calloc (14,1); //maximo nombre largo
	entradaLarga = (char *) calloc (32 * 2, 1);
	entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esDirectorio);

	iClus = ObtenerClusterDeDirectorio(path);
	struct cluster *st_clus;
	st_clus = (struct cluster *) malloc (sizeof(struct cluster));
	st_clus->numero = iClus;

	cola = CrearColaClusterDeEntradasDirectorio(st_clus);
	cantNodosCola = CantidadDeNodosCola(cola);
	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32; /* 32 tamaño de entradas */

	uint32_t noBorreArchivo = 1;

	for (i = 0; i < cantidadEntradas && noBorreArchivo; i++)
	{
		ptrCarpeta = (carpeta + (i * 32));
		if (memcmp(ptrCarpeta, entrada, 32) == 0)
		{
			noBorreArchivo = 0;
			clusterArchivo = UbicacionCarpeta(entrada);
			*(ptrCarpeta) = ATRIBUTO_BORRADO1;

			if (  *((carpeta + ((i-1) * 32)) + 11 ) == ATRIBUTO_LFN ) /* si la entrada anterior en LFN, la marco como borrada */
				*(carpeta + ((i-1) * 32)) = ATRIBUTO_BORRADO1;

			f = clusterArchivo;
			CrearColaBloqueFAT(bloques);

			if (clusterArchivo == 0)
			{	/* El archivo ya fue marcado como borrado y no tiene cluster asignados */
				/* Actualizo el cluster de la entrada modificada */
				clusterEnCola = i / 128;
				ptr = cola->frente;
				for (j = 0; j < clusterEnCola; j++)
					ptr = ptr->sgte;
				cluster1 = carpeta + (j * TAMANO_CLUSTER);
				if ( ptr != cola->final && nombreLargo == NULL)
				{
					cluster2 = carpeta + ((j+1) * TAMANO_CLUSTER);
					enviarCluster(ptr->sgte->numero, cluster2, 0);
				}
				enviarCluster(ptr->numero, cluster1, 0);
				/* fin de actualizar cluster de la entrada */

				log_info(log,"PFS","Se eliminó el archivo %s", path);

				/*libero la memoria de la cola */
				ptr = cola->frente;
				while (ptr!= NULL)
				{
					ptrAux = ptr;
					ptr = ptr->sgte;
					free(ptrAux);
				}


				free (carpeta);
				free (entradaLarga);
				free (nombreLargo);
				free (entrada);
				free (st_clus);

				return 0;
			}

			while (clusterArchivo < EOC_MINIMO)
			{
				MeterEnColaBloqueFAT(bloques, bloqueDeFat(f)); /* armo cola de bloques a la que pertenece i, para actualizar la fat (uso colacluster porque son las mismas funciones */
				/*el problema de MeterEnColaCLuster() es que pueden haber repetidos*/

				pthread_mutex_lock(&mutexFat); /* fixme */
				clusterArchivo = fat[f];
				fat[f] = FREE_CLUSTER;
				pthread_mutex_unlock(&mutexFat);

				pthread_mutex_lock(&mutexClustersLibres);
				MeterEnColaClusterLibres(clustersLibres, f);
				pthread_mutex_unlock(&mutexClustersLibres);

				f = clusterArchivo;


			}


		/* Actualizo el cluster de la entrada modificada */
			clusterEnCola = i / 128;
			ptr = cola->frente;
			for (j = 0; j < clusterEnCola; j++)
				ptr = ptr->sgte;
			cluster1 = carpeta + (j * TAMANO_CLUSTER);
			if ( ptr != cola->final && nombreLargo == NULL)
			{
				cluster2 = carpeta + ((j+1) * TAMANO_CLUSTER);
				enviarCluster(ptr->sgte->numero, cluster2, 0);
				free(cluster2);
			}

			enviarCluster(ptr->numero, cluster1, 0);
		/* fin de actualizar cluster de la entrada */

			actualizarEnFat(bloques);

			struct nodoColaBloquesFAT *ptrBloque, *ptrBloqueAux;
			ptrBloque = bloques->frente;
			while (ptrBloque != NULL)
			{
				ptrBloqueAux = ptrBloque;
				ptrBloque = ptrBloque->sgte;
				free(ptrBloqueAux);
			}

		/* ACA HAY QUE ACTUALIZA LA FAT EN EL DISCO */

		}
	}

	/*libero la memoria de la cola */
	ptr = cola->frente;
	while (ptr!= NULL)
	{
		ptrAux = ptr;
		ptr = ptr->sgte;
		free(ptrAux);
	}

	free (carpeta);
	free (entradaLarga);
	free (nombreLargo);
	free (entrada);
	free (st_clus);

	if ( i == cantidadEntradas)
	{
		log_info(log,"PFS","Se produjo un error al eliminar el archivo %s", path);
		return -1 ;
	}
	else
	{
		log_info(log,"PFS","Se eliminó el archivo %s", path);
		return 0;
	}

}

static uint32_t LasRamonas_mkdir (const char *path, mode_t mode)
{

	char *entrada, *entradaAux, *nombre, *carpeta, *cluster1, *cluster2, *subcarpeta;
	uint32_t cantNodosCola, iClus, cantidadEntradas, i, j, nuevoCluster, clusterEnCola, iClusLibre;
	struct colaCluster *cola;
	struct nodoColaCluster *ptr;
	struct cluster *st_clus;
	st_clus = (struct cluster *) malloc (sizeof(struct cluster));


	entradaAux = calloc (1,32); //32 bytes por entrada de directorio
//	entrada = (char *) malloc (64); //32 bytes por entrada de directorio
	nombre = (char *) malloc (14);
	subcarpeta = calloc(TAMANO_CLUSTER, sizeof(char) );
//	memset(entradaAux, 0, 32);

	nombre = obtenerNombreArchivoPath(path);

	entrada = ArmarEntradaNombreLargo(entradaAux, nombre);

	iClusLibre = SacarDeColaClusterLibres(clustersLibres);
	ArmarEntradaNombreCortoNueva(entrada + 32, nombre, iClusLibre, ATRIBUTO_DIRECTORIO);

	if ((iClus = ObtenerClusterDeDirectorio(path) )== 0)
	{/*error no existe el directorio destino*/
		iClus = bootSector->clusterRaiz;
	}


	st_clus->numero = iClus;
	cola = CrearColaClusterDeEntradasDirectorio(st_clus);

	cantNodosCola = CantidadDeNodosCola(cola);

	carpeta = calloc((cantNodosCola + 1) * TAMANO_CLUSTER, sizeof(char) );
	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32; /* 32 tamaño de entradas */

	for (i = 0; i < cantidadEntradas  &&  *(carpeta + (i * 32)) != 0 ; i++); // avanzo hasta el final o hasta encontrar una entrada vacía

	if (i >= cantidadEntradas - 1)
	{	// Si i es 4095 o 4096 debo agregar otro cluster a la carpeta para pegar el nombre largo
		// 4095 implica que solo hay un espacio y debo pegar 2
		// 4096 implica que la carpeta está llena y hay que agregar otro cluster para pegar la entrada

		nuevoCluster = AgregarUnClusterLibreAColaDeCluster(cola);
		cantNodosCola++;

	}
	memcpy(carpeta + (i * 32), entrada, 64);

	// "." y ".." El primer parámetro es el cluster del directorio actual
	// el segundo parámetro es el cluster del directorio padre
	CrearEntradaDeSubcarpeta(subcarpeta, &iClusLibre, &iClus);
	enviarCluster(iClusLibre, subcarpeta, 0);
	pthread_mutex_lock(&mutexFat);
	fat[iClusLibre] = EOC_MAXIMO;
	pthread_mutex_unlock(&mutexFat);

	clusterEnCola = i / 128;
	ptr = cola->frente;

	for (j = 0; j < clusterEnCola; j++)
		ptr = ptr->sgte;

	cluster1 = carpeta + (j * TAMANO_CLUSTER);
	if ( ptr != cola->final)
	{
		cluster2 = carpeta + ((j+1) * TAMANO_CLUSTER);
		enviarCluster(ptr->sgte->numero, cluster2, 0);
	}

	enviarCluster(ptr->numero, cluster1, 0);


	free(entradaAux);
//	free(entrada); //genera memory map
	free(carpeta);
	free(subcarpeta);
	log_info(log, "PFS", "Se creó el directorio %s", path);
	return 0;
}

static uint32_t LasRamonas_rmdir (const char *path)
{

	char *entrada, *nombre, *carpeta, *cluster1, *cluster2, *subcarpeta, *nombreLargo, esDirectorio;
	uint32_t cantNodosCola, iClus, cantidadEntradas, i, j, f, nuevoCluster, clusterEnCola, iClusSubcarpeta;
	struct colaCluster *cola;
	struct colaBloques *bloques;
	struct nodoColaCluster *ptr;

	entrada = (char *) malloc (64); //32 bytes por entrada de directorio
	nombre = (char *) malloc (14);
	nombreLargo = (char *) malloc (14);
	subcarpeta = calloc(TAMANO_CLUSTER, sizeof(char) );


	if ((iClus = ObtenerClusterDeDirectorio(path) )== 0)
	{/*error no existe el directorio destino*/}


	cola = CrearColaClusterDeEntradasDirectorio(iClus);
	cantNodosCola = CantidadDeNodosCola(cola);

	carpeta = calloc((cantNodosCola + 1) * TAMANO_CLUSTER, sizeof(char) );
	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32; /* 32 tamaño de entradas */

	entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esDirectorio);
	iClusSubcarpeta = UbicacionCarpeta(entrada);

	if (esCarpetaVacia(iClusSubcarpeta))
	{

		borrarTodasLasEntradasDeCarpeta(iClusSubcarpeta); //borra las entradas de la carpeta (borra ".", ".." y las entradas marcadas como borradas) pone todos 0;

		for (i = 0; i < cantidadEntradas && strcmp(entrada, carpeta + (i*32) ) != 0; i++);

		if (strcmp(entrada, carpeta + (i*32) ) == 0)
		{
			*(carpeta + (i*32)) = ATRIBUTO_BORRADO1; //marco la entrada como borrada
			if (nombreLargo != NULL)
				*(carpeta + ((i-1) * 32)) = ATRIBUTO_BORRADO1; //marco la entrada de nombre largo (la anterior) como borrada


			f = iClusSubcarpeta;
			CrearColaBloqueFAT(bloques);
			while (iClusSubcarpeta < EOC_MINIMO)
			{
				MeterEnColaBloqueFAT(bloques, bloqueDeFat(f)); /* armo cola de bloques a la que pertenece i, para actualizar la fat (uso colacluster porque son las mismas funciones */
				/*el problema de MeterEnColaCLuster() es que pueden haber repetidos*/

				pthread_mutex_lock(&mutexFat);
				iClusSubcarpeta = fat[f];
				fat[f] = FREE_CLUSTER;
				pthread_mutex_unlock(&mutexFat);

				pthread_mutex_lock(&mutexClustersLibres);
				MeterEnColaClusterLibres(clustersLibres, f);
				pthread_mutex_unlock(&mutexClustersLibres);

				f = iClusSubcarpeta;
			}



				/* Actualizo el cluster de la entrada modificada */
			clusterEnCola = i / 128;
			ptr = cola->frente;
			for (j = 0; j < clusterEnCola; j++)
				ptr = ptr->sgte;
			cluster1 = carpeta + (j * TAMANO_CLUSTER);
			if ( ptr != cola->final && nombreLargo == NULL)
			{
				cluster2 = carpeta + ((j+1) * TAMANO_CLUSTER);
				enviarCluster(ptr->sgte->numero, cluster2, 0);
			}

			enviarCluster(ptr->numero, cluster1, 0);
		/* fin de actualizar cluster de la entrada */

			actualizarEnFat(bloques);
		/* ACA HAY QUE ACTUALIZA LA FAT EN EL DISCO */


		}
		else {} // no encontré la entrada ERROR debería haberla encontrado, no puede ser que no esté

	}
	else
	{}	// la carpeta no está vacía. No se puede borrar la carpeta

	free(subcarpeta);
	free(carpeta);
	free(entrada);
	free(nombre);
	free(nombreLargo);
	return 0;
}

/* funciones necesarias faltantes de rename */




//char *ArmarEntradaNombreLargo(char *entradaAnterior, char *nombreNuevo); /* en base a la entrada original de 32 bytes y un nombre (que puede ser LFN o no), arma una entrada LFN con el nuevo nombre */
//char *obtenerNombreLargo(char *entrada); /* retorna el nombre del archivo LFN */
//void borrarEntradaArchivo_LFN(char *path); /* marca la entrada LFN del archivo como borrada */
  	  /* marca la entrada comun y la de nombre largo como borradas */
/* funciones faltantes de rename */


static uint32_t LasRamonas_rename (const char *viejo, const char *nuevo)
{
	char *entradaAnterior, *cluster, *cluster1, *cluster2, esDirectorio;
	char *nombreLargo, *carpeta, *nombreViejo, *nombreNuevo, *entradaNueva, *nombreAux;
	uint32_t iClus, i, j, cantNodosCola, cantidadEntradas, clusterEnCola;
	struct colaCluster *cola;
	struct nodoColaCluster *ptr;



	entradaAnterior = (char *) malloc (2 * 32); /* 32 es entrada de directorio y 2 por si es LFN */
	entradaNueva = (char *) malloc (2 * 32); /* 32 es entrada de directorio y 2 por si es LFN */
	nombreLargo = (char *) malloc (14); /* 13 + 1 */

	nombreViejo = (char *) malloc (14);
	nombreNuevo = (char *) malloc (14);
	nombreAux = (char *) malloc (14);
	uint32_t respuesta = 2;

	if (estaAbierto(viejo))
	{
		/* archivo viejo está en uso. no puede renombrarse*/
		return -1;
	}

	if (estaAbierto(nuevo))
	{
		/* archivo viejo está en uso. no puede renombrarse*/
		return -1;
	}

	entradaAnterior = ObtenerEntradaDeArchivo(viejo, nombreLargo, &esDirectorio);

	if ((iClus = ObtenerClusterDeDirectorio(nuevo) )== 0)
	{/*error no existe el directorio destino*/}

	if (iClus == ObtenerClusterDeDirectorio(viejo))
	{	// Solo renombrar el archivo sin mover
		// ver que pasa si paso de un nombre corto a un nombre largo
		return 0;
	}

	cola = CrearColaClusterDeEntradasDirectorio(iClus);
	cantNodosCola = CantidadDeNodosCola(cola);

	carpeta = calloc((cantNodosCola + 1) * TAMANO_CLUSTER, sizeof(char) );
	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32; /* 32 tamaño de entradas */

	obtenerNombre(viejo, nombreViejo);
	obtenerNombre(nuevo,nombreNuevo);
	obtenerNombre(carpeta + (i * 32), nombreAux);
/**/if (nombreLargo == NULL)	/* La entrada no es LONG FILE NAME */
	{
		entradaNueva = cambiarNombre (entradaAnterior, nombreNuevo);
		for (i = 0; i < cantidadEntradas
					&& strcmp(nombreAux, nombreNuevo) /* mientras no encuentre el nombre de archivo */
					&& *(carpeta + (i * 32)) != 0; /* No es entrada vacía */
					i++);

		if (!strcmp(nombreAux, nombreNuevo)) /* encontró archivo con el mismo nombre */
		{

			while (respuesta != 0 && respuesta != 1)
				scanf("Hay un archivo con ese nombre, quier sobreescribirlo?\n  0: no sobreescribe\n  1: sobrescribre\n", respuesta);
			if (respuesta == 1)
			{
				memcpy (carpeta + (i * 32), entradaNueva, 32);
				borrarEntradaArchivo(viejo);
			}
			else
			{/* No hace nada */}
		}

		if (*(carpeta + (i*32)) == 0) /* encontró espacio vacío */
		{
			memcpy (carpeta + (i * 32), entradaNueva, 32);
			borrarEntradaArchivo(viejo);
		}

		if (i == cantidadEntradas)
		{
			AgregarUnClusterLibreAColaDeCluster(cola);
			memcpy (carpeta + (i * 32), entradaNueva, 32);
			borrarEntradaArchivo(viejo);
			i++;
		}

		clusterEnCola = i / 128; /*128 es cantidad de entradas por cluster */
		ptr = cola->frente;
		for (j = 0; j < clusterEnCola; j++)
			ptr = ptr->sgte;
		cluster = carpeta + (j * TAMANO_CLUSTER);

		enviarCluster(ptr->numero, cluster, 0);
	}
/**/else /*  La entrada es LONG FILE NAME nombreLargo != NULL*/
	{
		entradaNueva = ArmarEntradaNombreLargo(entradaAnterior, nombreNuevo);
		obtenerNombreLargo(carpeta + (i * 32), nombreAux);
		for (i = 0; i < cantidadEntradas
					&& strcmp(nombreAux, nombreNuevo) /* mientras no encuentre el nombre de archivo */
					&& *(carpeta + (i * 32)) != 0; /* No es entrada vacía */
					i++);

		if (!strcmp(nombreAux, nombreNuevo)) /* encontró archivo con el mismo nombre */
				{

					while (respuesta != 0 && respuesta != 1)
						scanf("Hay un archivo con ese nombre, quier sobreescribirlo?\n0: no sobreescribe\n1: sobrescribre\n", respuesta);
					if (respuesta == 1)
					{
						memcpy (carpeta + (i * 32), entradaNueva, 64);
						borrarEntradaArchivo_LFN(viejo);
					}
					else
					{/* No hace nada */}
				}

		if (*(carpeta + (i*32)) == 0) /* encontró espacio vacío */
				{
					memcpy (carpeta + (i * 32), entradaNueva, 64);
					i = i + 2;
					borrarEntradaArchivo_LFN(viejo);
				}

		if (i == cantidadEntradas)
				{
					AgregarUnClusterLibreAColaDeCluster(cola);
					memcpy (carpeta + (i * 32), entradaNueva, 64);
					i = i + 2;
					borrarEntradaArchivo_LFN(viejo);
				}
		clusterEnCola = i / 128;
		ptr = cola->frente;

		for (j = 0; j < clusterEnCola; j++)
			ptr = ptr->sgte;

		cluster1 = carpeta + (j * TAMANO_CLUSTER);
		if ( ptr != cola->final)
		{
			cluster2 = carpeta + ((j+1) * TAMANO_CLUSTER);
			enviarCluster(ptr->sgte->numero, cluster2, 0);
		}

		enviarCluster(ptr->numero, cluster1, 0);
	}


	free(entradaAnterior);
	free(entradaNueva);
	free(nombreLargo);
	free(nombreNuevo);
	free(nombreViejo);
	free(carpeta);
	return 0;

}

static struct fuse_operations LasRamonas_oper = {
    .getattr   = LasRamonas_getattr,
    .readdir = LasRamonas_readdir,
    .open   = LasRamonas_open,
    .read   = LasRamonas_read,
    .create = LasRamonas_create,
    .write = LasRamonas_write,
    .flush = LasRamonas_flush,
    .release = LasRamonas_release,
    .truncate = LasRamonas_truncate,
    .unlink = LasRamonas_unlink,
    .mkdir = LasRamonas_mkdir,
    .rmdir = LasRamonas_rmdir,
    .rename = LasRamonas_rename,

};


  uint32_t main(uint32_t argc, char *argv[])
  {


	  //Esto genera un thread y hace que la consola corra en otro thread y permite que sigamos con el flujo normal del main

 	  log =  log_create("Runner", LOGPATH, ERROR | DEBUG | INFO | WARNING, M_CONSOLE_DISABLE);

	  signal (SIGUSR1, &flushToFile);

	 pthread_t idHilo;
	 pthread_create(&idHilo, NULL,(void *) &generarConsola, NULL);

	  if (!(iniciarEstructuraConfiguracion(estructuraConfiguracion))){
	  	  printf("No se pudo procesar el archivo de configuracion");
	  	  log_error(log, "PFS", "Message error: %s", "No se pudo procesar el archivo de configuracion");
	  	  log_destroy(log);
	  	  return 1;
	  	}

	  pthread_mutex_init(&mutexDireccionamiento, NULL);
	  generarColaConexiones();
	  log_info (log, "PFS", "Se está leyendo el Boot Sector");
	  printf("\nLeyendo Boot Sector.....\n");
	  leerBootSector();
	  printf("OK\n\n");
	  log_info(log, "PFS", "Se está leyendo la FAT REGION");
	  printf("Leyendo FAT Region.....\n");
	  leerFat();
	  printf("OK\n\n");
	  CrearColaClusterLibres();

	  printf("Datos del archivo de configuración:\n\n");
	  printf("IP remota: %s \n", config.sIPConex);
	  printf("Puerto remoto: %d \n", config.iPuertoConex);
	  printf("Cantidad máxima de conexiones: %d \n", config.iCantMaxConex);
	  printf("Tamaño de la Cache: %d Kb \n", config.iTamCache);


	  archivosAbiertos   = NULL;  /* inicio la lista de archivos abiertos */


	  printf("Llamando a FUSE en el punto de montaje %s\n\0\0", argv[1] );
      return fuse_main(argc, argv, &LasRamonas_oper, NULL);



      /*
       * valores del type:
       * 0) handshake
       * 1) Escribirprobar
       * 2) Leer
       *
       * 3) Respuesta del ppd/raid para el filesystem*/

}
